<template>
    <div class="DragBox" ref="DragBox" id="TreeDragBox" data-treecomp-id="Stop" :style="{
        padding: token.padding + 'px 0'
    }">
        <DragItem v-for="item in TreeData" :TreeMap="ChildMap" :Config="item" :level="0" />
    </div>
    <div class="DragMark" ref="DragMark">
        <div class="HoverMark" v-if="HoverMarkLineTop !== null" :style="{
            background: token.colorPrimaryBorder,
            ...HoverMarkStyle
        }">
            <div class="Star" :style="{
                borderColor: token.colorPrimaryBorder,
            }"></div>
            <div class="End" :style="{
                borderColor: token.colorPrimaryBorder,
            }"></div>
        </div>
        <div class="MarkBlock" v-if="MoveState == 'inside'" :style="{
            ...MarkBlockStyle,
            borderColor: token.colorPrimaryBorder,
            borderRadius: token.borderRadius + 'px',
        }">
        </div>
    </div>
    <div class="DragMove" v-if="DragMovePosition.title" :style="{
        background: token.colorPrimaryBg,
        boxShadow: token.boxShadowSecondary,
        padding: token.paddingXS + 'px',
        borderRadius: token.borderRadius + 'px',
        top: DragMovePosition.y + 'px',
        left: DragMovePosition.x + 'px',
    }">
        {{ DragMovePosition.title }}
    </div>
</template>

<script setup>
import DragItem from './DragItem.vue';
import { watch, watchEffect, provide, ref, onMounted, onUnmounted } from 'vue'
import { theme } from 'ant-design-vue';
const { token } = theme.useToken();

const props = defineProps(['ChildMap', 'TreeData']);
const emit = defineEmits(['ItemClick']);
const DragBox = ref();
const DragMark = ref();




let TreeItemMapping = {};
var recursion = function (List, level = 0, parentId) {
    for (let i = 0; i < List.length; i++) {
        const element = List[i];
        TreeItemMapping[element.id] = element;
        element._level = level;
        element._parent = parentId;
        if (element.children && element.children.length) {
            recursion(element.children, level + 1, element.id)
        }
    }
};



watch(() => props.TreeData, value => {
    TreeItemMapping = {};
    recursion(value);
}, { immediate: true });

const GetEventTargetId = function (event) {
    var id = event.getAttribute('data-treecomp-id');
    if (id == 'Stop') {
        return null;
    } else if (!id) {
        return GetEventTargetId(event.parentNode);
    } else {
        return { id, event }
    }
}

let MarkValue = ref(0);
onMounted(() => {
    const DragBoxTop = (DragBox.value.getBoundingClientRect()).top;
    const DragMarkTop = (DragMark.value.getBoundingClientRect()).top;
    MarkValue.value = Math.abs(DragBoxTop - DragMarkTop);
})


let DragMoveState = true;
const HoverMarkLineTop = ref(null);
const HoverMarkLineLeft = ref(null);
const DragState = ref(false);
provide('DragState', DragState);

const ChildMapping = {};
provide('SetChildItem', function (key, Event) {
    ChildMapping[key] = Event;
});

const MouseLeaveEvent = function (event) { DragMoveState = false; };


const DragActiveItem = ref(null);
provide('DragActiveItem', DragActiveItem);
const DragActiveCache = ref(null);

const MoveState = ref(null);
const MoveToId = ref(null);
const MoveFormId = ref(null);

const DragMovePosition = ref({ x: 0, y: 0, title: null });

watch(DragActiveItem, value => {
    if (value) {
        const HoverObject = TreeItemMapping[value];
        DragMovePosition.value.title = HoverObject.originalTitle;
    } else {
        DragMovePosition.value.title = null;
    }
})

const HoverMarkStyle = ref({});

const MarkBlockStyle = ref({});
const MarkBlockRect = ref({});
watchEffect(() => {
    if (DragState.value && MoveState.value == 'inside') {
        var _l = HoverMarkLineLeft.value * 16 + 8;
        MarkBlockStyle.value.width = MarkBlockRect.value.width - _l + 8 + 'px';
        MarkBlockStyle.value.height = MarkBlockRect.value.height + 'px';
        MarkBlockStyle.value.left = _l + 'px';
        MarkBlockStyle.value.top = MarkBlockRect.value.y + 'px';
    } else {
        MarkBlockStyle.value = {};
    }
    if (DragState.value && MoveState.value != 'inside') {
        var _l = HoverMarkLineLeft.value * 16 + 16;
        HoverMarkStyle.value.width = MarkBlockRect.value.width - _l + 'px';
        HoverMarkStyle.value.left = _l + 'px';
        HoverMarkStyle.value.top = HoverMarkLineTop.value + 'px';
    } else {
        HoverMarkStyle.value = {};
    }
});




const DragDetectionEvent = function (event) {
    DragMoveState = true;
    if (Math.abs(MouseMovePosition.x - event.pageX) > 5 || Math.abs(MouseMovePosition.y - event.pageY) > 5) {
        DragState.value = true;
        MoveFormId.value = DragActiveCache.value;
        DragActiveItem.value = DragActiveCache.value
    };
    if (DragState.value) {
        DragMovePosition.value.x = event.pageX;
        DragMovePosition.value.y = event.pageY;

        const ChooseBox = GetEventTargetId(event.target);
        if (ChooseBox) {
            const Rect = ChooseBox.event.getBoundingClientRect();
            MarkBlockRect.value = Rect;
            const HoverObject = TreeItemMapping[ChooseBox.id];
            MoveToId.value = ChooseBox.id;
            HoverMarkLineLeft.value = HoverObject._level || 0;
            if (HoverObject.formType == 'group') {
                ChildMapping[ChooseBox.id].OpenFolder();
                const LittleHeight = Rect.height / 3;
                if (event.offsetY < LittleHeight) {
                    MoveState.value = 'top';
                    HoverMarkLineTop.value = Rect.top + 1;
                } else if (event.offsetY > LittleHeight * 2 && !(HoverObject.children && HoverObject.children.length > 0)) {
                    MoveState.value = 'bottom';
                    HoverMarkLineTop.value = Rect.bottom - 1;
                } else {
                    MoveState.value = 'inside';
                    HoverMarkLineTop.value = null;
                }
            } else {
                const HrefHeight = Rect.height / 2;
                if (event.offsetY < HrefHeight) {
                    MoveState.value = 'top';
                    HoverMarkLineTop.value = Rect.top + 1;
                } else {
                    MoveState.value = 'bottom';
                    HoverMarkLineTop.value = Rect.bottom - 1;
                }
            }
        } else { }
    }
}


let MouseMovePosition = { x: 0, y: 0 };
const MouseDownEvent = function (event) {
    const ChooseBox = GetEventTargetId(event.target);
    if (ChooseBox) {
        DragActiveCache.value = ChooseBox.id;
    };
    MouseMovePosition.x = event.pageX;
    MouseMovePosition.y = event.pageY;
    DragBox.value.addEventListener('mousemove', DragDetectionEvent);
    DragBox.value.addEventListener('mouseleave', MouseLeaveEvent);
};


const ActiveObject = ref();
provide('ActiveObject', ActiveObject)


// 点击事件相关 (拖拽时,不执行点击事件)
const MouseUpClickEvent = function (event) {
    if (!DragState.value) {
        const ChooseBox = GetEventTargetId(event.target);
        if (ChooseBox && ChildMapping[ChooseBox.id]) {
            var _e = ChildMapping[ChooseBox.id];
            var value = _e.ClickEvent();
            if (value) {
                ActiveObject.value = value;
                emit('ItemClick', value);
            }
        }
    };
    if (DragMoveState && DragState.value) {
        const ChooseBox = GetEventTargetId(event.target);
    };
};

const ReSetData = function () {
    setTimeout(() => {
        MoveFormId.value = null;
        MoveToId.value = null;
        MoveState.value = null;

        DragMoveState = false;

        DragState.value = false;
        HoverMarkLineTop.value = null;
        DragActiveItem.value = null;

        DragBox.value && DragBox.value.removeEventListener('mousemove', DragDetectionEvent);
        DragBox.value && DragBox.value.removeEventListener('mouseleave', MouseLeaveEvent);
    }, 1)
};

onMounted(() => {
    DragBox.value.addEventListener('mousedown', MouseDownEvent);
    DragBox.value.addEventListener('mouseup', MouseUpClickEvent);
    window.addEventListener('mouseup', ReSetData);
});
onUnmounted(() => {
    DragBox.value && DragBox.value.removeEventListener('mousedown', MouseDownEvent);
    DragBox.value && DragBox.value.removeEventListener('mouseup', MouseUpClickEvent);
    window.removeEventListener('mouseup', ReSetData);
});


defineExpose({
    'SetActiveObject': function (data) {
        ActiveObject.value = { ...data };

        function Each(data) {
            if (data._parent && ChildMapping[data._parent]) {
                ChildMapping[data._parent].OpenFolder();
                var _data = TreeItemMapping[data._parent];
                if (_data) {
                    Each(_data)
                }
            };
        }
        setTimeout(() => {
            Each(data)
        }, 100);
    }
})


</script>

<style lang="less" scoped>
.MarkBlock {
    position: fixed;
    border: 2px solid;
}

.DragMove {
    position: fixed;
    transform: translate(10px, 10px);
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.DragBox {
    position: relative;
    height: 100%;
    overflow-y: auto;
}

.HoverMark {
    position: fixed;
    height: 2px;
    left: 0;
    background-color: aqua;

    .Star,
    .End {
        position: absolute;
        width: 8px;
        height: 8px;
        border: 2px solid #ccc;
        border-radius: 50%;
        left: -7px;
        top: -3px;
    }

    .End {
        left: auto;
        right: -7px;
        top: -3px;
    }
}

.DragMark {
    pointer-events: none;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
}
</style>